using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Threading.Tasks;
using AvaloniaApplication1.IServices;
using AvaloniaApplication1.Models;
using AvaloniaApplication1.Util;
using Modbus.Device;

namespace AvaloniaApplication1.Service;

public class ModbusManager : IModbusManager
{
    private readonly ConcurrentDictionary<string, ModbusConfig> _modbusDevices = new();
    /// <summary>
    /// 正在读取的设备
    /// </summary>
    // private readonly ConcurrentDictionary<string, bool> _readingRegisters = new();

    /// <summary>
    /// 检查tcp连接端口是否存在
    /// </summary>
    /// <param name="deviceName"></param>
    /// <param name="tcpName"></param>
    /// <returns></returns>
    public async Task<bool> CheckPortExistsAsync(string deviceName, string tcpName)
    {
        return await Task.Run(() =>
        {
            if (!_modbusDevices.ContainsKey(deviceName))
            {
                AppLogger.Information($"Message from ModbusManager: Device {deviceName} already exists");
                return false;
            }

            if (!_modbusDevices[deviceName].TcpConfig.Ports.ContainsKey(tcpName)) return true;
            AppLogger.Information($"Message from ModbusManager: Port {tcpName} already exists");
            return false;
        });
    }

    /// <summary>
    /// 添加modbus 设备
    /// </summary>
    /// <param name="modbusConfig">modbus设备</param>
    /// <returns></returns>
    public async Task<bool> AddModbusDeviceAsync(ModbusConfig modbusConfig)
    {
        try
        {
            if (_modbusDevices.ContainsKey(modbusConfig.DeviceName))
            {
                AppLogger.Information($"Message from ModbusManager: Device {modbusConfig.DeviceName} already exists");
                return false;
            }

            //modbusConfig.TcpConfig.Ports检查与_modbusDevices中的TcpConfig.Ports是否存在
            var portExists = await CheckPortExistsAsync(modbusConfig.DeviceName, modbusConfig.TcpConfig.TcpName);
            if (portExists)
            {
                AppLogger.Information($"Message from ModbusManager: tcpCheck exists");
                return false;
            }

            // 添加modbus设备
            _modbusDevices[modbusConfig.DeviceName] = modbusConfig;
            ModbusDeviceAdded?.Invoke(this,new ModbusDeviceEventArgs(modbusConfig) );
            AppLogger.Information($"Message from ModbusManager: Device {modbusConfig.DeviceName} added successfully");
            return true;
        }
        catch (Exception e)
        {
            AppLogger.Error(e, $"Message from ModbusManager: Error in AddModbusDeviceAsync currentTime-{DateTime.Now}");
            return false;
        }
    }

    /// <summary>
    /// 删除modbus 设备
    /// </summary>
    /// <param name="deviceName"></param>
    /// <returns></returns>
    public async Task<bool> RemoveModbusDeviceAsync(string deviceName)
    {
        try
        {
            if (!_modbusDevices.ContainsKey(deviceName))
            {
                AppLogger.Information($"Device {deviceName} not exists");
                return false;
            }

            _modbusDevices.TryRemove(deviceName, out var device);
            if (device != null) ModbusDeviceRemoved?.Invoke(this, new ModbusDeviceEventArgs(device));
            AppLogger.Information($"Message from ModbusManager: Device {deviceName} removed successfully");
            return true;
        }
        catch (Exception e)
        {
            AppLogger.Error(e,
                $" Message from ModbusManager: Error in RemoveModbusDeviceAsync currentTime-{DateTime.Now}");
            return false;
        }
    }
    /// <summary>
    /// 连接modbus设备
    /// </summary>
    /// <param name="deviceName"></param>
    /// <param name="tcpName"></param>
    /// <returns></returns>
    public async Task<bool> ConnectModbusDeviceAsync(string deviceName, string tcpName)
    {
        try
        {
            if (!_modbusDevices.ContainsKey(deviceName))
            {
                AppLogger.Information($"Message from ModbusManager: Device {deviceName} not exists");
                return false;
            }

            if (_modbusDevices[deviceName].ConnectionType == ModbusConnectionType.RtuOverTcp)
            {
                var tcpClient = new TcpClient();
                tcpClient.ReceiveTimeout = _modbusDevices[deviceName].TcpConfig.Timeout;
                await tcpClient.ConnectAsync(_modbusDevices[deviceName].TcpConfig.Server,
                    _modbusDevices[deviceName].TcpConfig.Ports[tcpName]);
                var tcpModbusMaster = ModbusSerialMaster.CreateRtu(tcpClient);
                if (tcpModbusMaster != null)
                {
                    _modbusDevices[deviceName].Master = tcpModbusMaster;
                    _modbusDevices[deviceName].IsConnected = true;
                    return true;
                }
            }

            if (_modbusDevices[deviceName].ConnectionType == ModbusConnectionType.Rtu)
            {
                var serialPort = new SerialPort(_modbusDevices[deviceName].SerialConfig.SerialName,
                    _modbusDevices[deviceName].SerialConfig.BaudRate,
                    _modbusDevices[deviceName].SerialConfig.Paritys,
                    _modbusDevices[deviceName].SerialConfig.DataBits);
                serialPort.ReadTimeout = _modbusDevices[deviceName].SerialConfig.ReadTimeout;
                serialPort.WriteTimeout = _modbusDevices[deviceName].SerialConfig.WriteTimeout;
                serialPort.StopBits=_modbusDevices[deviceName].SerialConfig.StopBits;
                try
                {
                    serialPort.Open();
                    var serialModbusMaster = ModbusSerialMaster.CreateRtu(serialPort);
                    return true;
                }
                catch (Exception e)
                {
                  AppLogger.Warning("Message from ModbusManager: Error in ConnectModbusDeviceAsync currentTime-{DateTime.Now} Serial Open is Error");
                  return false;
                }
                
            }

            AppLogger.Information($"Message from ModbusManager: Device {deviceName} not supported");
            return false;
        }
        catch (Exception e)
        {
            AppLogger.Error(e,
                $" Message from ModbusManager: Error in ConnectModbusDeviceAsync currentTime-{DateTime.Now}");
            return false;
        }
    }

    /// <summary>
    /// 断开modbus设备
    /// </summary>
    public Task<bool> DisconnectModbusDeviceAsync(string deviceName)
    {
        if (!_modbusDevices.ContainsKey(deviceName))
        {
            AppLogger.Information($"Message from ModbusManager: Device {deviceName} not exists");
            return Task.FromResult(false);
        }
        _modbusDevices[deviceName].IsConnected = false;

        //_modbusDevices[deviceName].Master?.Dispose();
        _modbusDevices[deviceName].Master = null; 
        AppLogger.Information($"Message from ModbusManager: Device {deviceName} disconnected successfully");
        return Task.FromResult(true);
    }

    /// <summary>
    /// 读取modbus设备保持寄存器
    /// </summary>
    /// <param name="deviceName">设备名称</param>
    /// <returns></returns>
    public async Task<ushort[]> ReadHoldingRegistersAsync(string deviceName)
    {
        // // 防止重复读取
        // if (_readingRegisters.ContainsKey(deviceName) && _readingRegisters[deviceName])
        //     return [];
        
        
        try
        {
            // if (_modbusDevices[deviceName].SlaveConfig.FunctionCode == 3)
            // {
            // 这个判断留在谁调用，谁判断
            // }
            // var checkSlaveIdResult= await CheckSlaveIdExistsAsync(deviceName, slaveId);
            // if (!checkSlaveIdResult) return [];
            
            // 在这行代码执行时，如果 deviceName 不存在，才会创建键值对
            // _readingRegisters[deviceName] = true;
            
            var slaveInfo = _modbusDevices[deviceName].SlaveInfo;
            var registers = await _modbusDevices[deviceName].Master.ReadHoldingRegistersAsync(
                slaveInfo.SlaveId
                , slaveInfo.StartAddress,
                slaveInfo.ReadRegisterCount
            );
            for (int i = 0; i < registers.Length ; i++)
            {
                slaveInfo.DataPoints[i].ReisterValue = registers[i];
                slaveInfo.DataPoints[i].LastUpdateTime=DateTime.Now;
            }
            
            return registers;
        }
        catch (Exception e)
        {
            AppLogger.Error(e,
                $" Message from ModbusManager: Error in ReadHoldingRegistersAsync currentTime-{DateTime.Now}");
            return [];
        }
        // finally
        // {
        //     _readingRegisters[deviceName] = false;
        // }
    }

    /// <summary>
    /// 配置modbus从站
    /// </summary>
    /// <param name="deviceName">设备名称</param>
    /// <returns></returns>
    public async Task<bool> SlaveConfigureDeviceAsync(string deviceName,byte slaveId,ushort slaveStartAddress, ushort slaveCount,int intervalTime)
    {
        if (!_modbusDevices.ContainsKey(deviceName)) return false;
        var slaveInfo = _modbusDevices[deviceName].SlaveInfo;
        slaveInfo.SlaveId = slaveId;
        slaveInfo.StartAddress = slaveStartAddress;
        slaveInfo.ReadRegisterCount = slaveCount;
        slaveInfo.IntervalTime = intervalTime;
        return true;
    }
    /// <summary>
    /// 配置modbus设备的tcp配置
    /// </summary>
    /// <param name="deviceName">设备名称</param>
    /// <param name="serverip">ip地址</param>
    /// <param name="tcpname">连接名称</param>
    /// <param name="ports">端口列表</param>
    /// <param name="timeout">超时时间</param>
    /// <returns></returns>
    public async Task<bool> ConfigureDeviceAsync(string deviceName, string serverip,string tcpname,Dictionary<string, int> ports,int timeout )
    {
        if (!_modbusDevices.ContainsKey(deviceName)) return false;
        var tcpconfig=_modbusDevices[deviceName].TcpConfig;
        tcpconfig.Server=serverip;
        tcpconfig.TcpName=tcpname;
        tcpconfig.Timeout=timeout;
        tcpconfig.Ports=ports;
        return true;
    }

    /// <summary>
    /// 写入modbus设备保持寄存器
    /// </summary>
    /// <param name="deviceName">设备名称</param>
    /// <param name="slaveId">从站id</param>
    /// <param name="writeRegisterAddress">写入的寄存器地址</param>
    /// <param name="valueToWrite">写入的值</param>
    /// <returns></returns>
    public async Task<bool> WriteSingleHoldingRegistersAsync(string deviceName, byte slaveId,ushort writeRegisterAddress,ushort valueToWrite)
    {
       
         await _modbusDevices[deviceName].Master.WriteSingleRegisterAsync(slaveId, writeRegisterAddress, valueToWrite);
         AppLogger.Information($"Message from ModbusManager: WriteHoldingRegistersAsync currentTime-{DateTime.Now}");
        return true;
    }
    /// <summary>
    /// 连续写入modbus设备多个保持寄存器
    /// </summary>
    /// <param name="deviceName">设备名称</param>
    /// <param name="slaveId">从站id</param>
    /// <param name="writeRegisterAddress">写入的寄存器地址</param>
    /// <param name="values">写入的数组</param>
    /// <returns></returns>
    public async Task<bool> WriteMultipleHoldingRegistersAsync(string deviceName,byte slaveId,ushort writeRegisterAddress, ushort[] values)
    {
        await _modbusDevices[deviceName].Master.WriteMultipleRegistersAsync(slaveId, writeRegisterAddress, values);
        AppLogger.Information($"Message from ModbusManager: WriteMultipleHoldingRegistersAsync currentTime-{DateTime.Now}");
        return true;
    }

    /// <summary>
    /// 获取modbus设备
    /// </summary>
    /// <param name="deviceName">设备名称</param>
    /// <returns></returns>
    public ModbusConfig? GetModbusDevice(string deviceName)
    {
        return _modbusDevices.ContainsKey(deviceName) ? _modbusDevices[deviceName] : null;
    }

    public async  Task<IEnumerable<ModbusConfig>>  GetAllModbusDevices()
    {
        return _modbusDevices.Values;
    }

    public bool ContainsModbusDevice(string deviceName)
    {
        return _modbusDevices.ContainsKey(deviceName);
    }

    public event EventHandler<ModbusDeviceStatusEventArgs>? ModbusDeviceStatusChanged;
    public event EventHandler<DeviceDataEventArgs>? ModbusDeviceDataReceived;
    public event EventHandler<ModbusDeviceEventArgs>? ModbusDeviceAdded;
    public event EventHandler<ModbusDeviceEventArgs>? ModbusDeviceRemoved;
}